package com.rfid.transport;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

public class Transport_Hid implements IComm {
    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    private static UsbManager manager = null;
    private static Context mContext = null;
    private UsbDeviceConnection mDeviceConnection = null;
    private UsbEndpoint epOut = null;
    private UsbEndpoint epIn = null;
    private int mMaxInSize = 64;
    private int mMaxOutSize = 64;
    private static Vector<UsbDevice> theUsbList = new Vector();
    static final String HIDTAG = "HIDTAG";
    private UsbInterface mInterface = null;

    @SuppressLint("WrongConstant")
    public static int ListUsbDevice(Context ctx) {
        theUsbList.clear();
        mContext = ctx;
        manager = (UsbManager) mContext.getSystemService("usb");
        if (manager == null) return 0;
        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        ArrayList<String> USBDeviceList = new ArrayList<String>();
        while (deviceIterator.hasNext()) {
            UsbDevice device = (UsbDevice) deviceIterator.next();
            USBDeviceList.add(String.valueOf(device.getVendorId()));
            USBDeviceList.add(String.valueOf(device.getProductId()));
            if (device.getVendorId() == 65534 && device.getProductId() == 145)
                theUsbList.add(device);
        }
        return theUsbList.size();
    }

    public static String GetUsbDescription(int idx) {
        if (idx < 0) return "";
        if (idx >= theUsbList.size()) return "";
        return ((UsbDevice) theUsbList.get(idx)).toString();
    }

    public static boolean requestUsbPermission(String usbDes) {
        if (theUsbList.size() <= 0) return false;
        UsbDevice device = null;
        if (usbDes.equals("")) device = (UsbDevice) theUsbList.get(0);
        else {
            int index = Integer.parseInt(usbDes);
            if (index >= theUsbList.size()) return false;
            device = (UsbDevice) theUsbList.get(index);
        }
        if (device == null) return false;
        PendingIntent mPendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("com.android.example.USB_PERMISSION"), 0);
        manager.requestPermission(device, mPendingIntent);
        return true;
    }

    private void getEndpoint(UsbDeviceConnection connection, UsbInterface intf) {
        if (intf.getEndpoint(1) != null) {
            this.epOut = intf.getEndpoint(1);
            this.mMaxOutSize = this.epOut.getMaxPacketSize();
        }
        if (intf.getEndpoint(0) != null) {
            this.epIn = intf.getEndpoint(0);
            this.mMaxInSize = this.epIn.getMaxPacketSize();
        }
    }

    public static boolean hasUsbPermission(String usbDes) {
        if (theUsbList.size() <= 0) return false;
        UsbDevice device = null;
        if (usbDes.equals("")) device = (UsbDevice) theUsbList.get(0);
        else {
            int index = Integer.parseInt(usbDes);
            if (index >= theUsbList.size()) return false;
            device = (UsbDevice) theUsbList.get(index);
        }
        if (device == null) return false;
        return manager.hasPermission(device);
    }

    public int Connect(String usbDes) {
        UsbDevice usbDevice = null;
        if (theUsbList.size() <= 0) return -3;
        if (usbDes.equals("")) usbDevice = (UsbDevice) theUsbList.get(0);
        else {
            int index = Integer.parseInt(usbDes);
            if (index >= theUsbList.size()) return -3;
            usbDevice = (UsbDevice) theUsbList.get(index);
        }
        if (usbDevice == null) return -3;
        if (usbDevice.getInterfaceCount() <= 0) return -2;
        UsbInterface intf = usbDevice.getInterface(0);
        UsbDeviceConnection connection = null;
        if (manager.hasPermission(usbDevice)) {
            connection = manager.openDevice(usbDevice);
            if (connection == null) return -2;
            if (connection.claimInterface(intf, true)) {
                this.mDeviceConnection = connection;
                this.mInterface = intf;
                getEndpoint(this.mDeviceConnection, this.mInterface);
                return 0;
            }
            connection.close();
            this.mDeviceConnection = null;
            this.mInterface = null;
            return -2;
        }
        this.mDeviceConnection = null;
        return -2;
    }

    public int DisConnect() {
        if (this.mDeviceConnection != null) {
            this.mDeviceConnection.releaseInterface(this.mInterface);
            this.mDeviceConnection.close();
            this.mDeviceConnection = null;
        }
        return 0;
    }

    private int SendRaw(byte[] buffer, int bufferLen, int mTimeout) {
        int ret = 0;
        int offset = 0;
        int mSendLeave = bufferLen;
        int mTryCnt = 3;
        while (mSendLeave > 0 && mTryCnt > 0) {
            ret = this.mDeviceConnection.bulkTransfer(this.epOut, buffer, offset, mSendLeave, mTimeout);
            if (ret > 0) {
                mSendLeave -= ret;
                offset += ret;
                continue;
            }
            mTryCnt--;
            try {
                Thread.sleep(5L);
            } catch (InterruptedException interruptedException) {
            }
            if (mTryCnt <= 0) return -1;
        }
        return offset;
    }

    private byte[] ReadRaw(int mTimeout) {
        byte[] Receiveytes = new byte[this.mMaxInSize];
        int ret = this.mDeviceConnection.bulkTransfer(this.epIn, Receiveytes, Receiveytes.length, mTimeout);
        if (ret <= 0) return null;
        return Arrays.copyOf(Receiveytes, ret);
    }

    public int Send(byte[] buffer, int offset, int bytesToWrite) {
        if (offset + bytesToWrite > buffer.length) return -3;
        if (this.mDeviceConnection == null) return -2;
        int send = 0;
        while (bytesToWrite > 0) {
            int BatchesLen = bytesToWrite;
            if (BatchesLen > this.mMaxOutSize - 1) BatchesLen = this.mMaxOutSize - 1;
            byte[] m_HIDOutReport = new byte[this.mMaxOutSize];
            m_HIDOutReport[0] = (byte) BatchesLen;
            System.arraycopy(buffer, offset + send, m_HIDOutReport, 1, BatchesLen);
            int dwWritten = SendRaw(m_HIDOutReport, BatchesLen + 1, 500);
            if (dwWritten <= 0) return -2;
            send += dwWritten;
            bytesToWrite -= dwWritten;
        }
        return 0;
    }

    public int Receive(byte[] bufferRead, int LenToRecv) {
        if (bufferRead.length < LenToRecv) return -2;
        if (this.mDeviceConnection == null) return -2;
        byte[] m_HIDInReport = ReadRaw(2000);
        int mReaded = 0;
        int mBufferLen = 0;
        while (m_HIDInReport != null && m_HIDInReport.length - mReaded > 2) {
            int RecvReportLen = m_HIDInReport[0];
            mReaded++;
            if (RecvReportLen + mReaded > m_HIDInReport.length) break;
            if (RecvReportLen > LenToRecv) RecvReportLen = LenToRecv;
            System.arraycopy(m_HIDInReport, mReaded, bufferRead, mBufferLen, RecvReportLen);
            mBufferLen += RecvReportLen;
            mReaded += RecvReportLen;
        }
        return mBufferLen;
    }

    public void ResetInputStream() {
        do {
        } while (ReadRaw(2) != null);
    }
}
